﻿#region 命名空间

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;

#endregion

namespace Sharp.Infrastructure.IoC
{
    /// <summary>
    ///  服务定位器
    /// </summary>
    public sealed class ServiceLocator : IServiceProvider
    {
        #region 私有字段

        private static readonly ServiceLocator instance = new ServiceLocator();
        private static readonly IUnityContainer Container = new UnityContainer();

        #endregion

        #region 构造函数

        /// <summary>
        ///     Initializes a new instance of <c>ServiceLocator</c> class.
        /// </summary>
        static ServiceLocator()
        {
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");

            section.Configure(Container);
        }

        #endregion

        #region 属性

        /// <summary>
        /// 获取单例实现
        /// </summary>
        public static ServiceLocator Instance
        {
            get { return instance; }
        }

        #endregion

        #region 方法

        private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments)
        {
            List<ParameterOverride> overrides = new List<ParameterOverride>();
            Type argumentsType = overridedArguments.GetType();
            argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .ToList()
                .ForEach(property =>
                {
                    var propertyValue = property.GetValue(overridedArguments, null);
                    var propertyName = property.Name;
                    overrides.Add(new ParameterOverride(propertyName, propertyValue));
                });
            return overrides;
        }
         
        public bool IsRegistered<T>()
        {
            return Container.IsRegistered<T>();
        }
        /// <summary>
        ///     Gets the service instance with the given type.
        /// </summary>
        /// <typeparam name="T">The type of the service.</typeparam>
        /// <returns>The service instance.</returns>
        public T GetService<T>()
        {

            return Container.Resolve<T>();
        }

        /// <summary>
        ///     Gets the service instance with the given type by using the overrided arguments.
        /// </summary>
        /// <typeparam name="T">The type of the service.</typeparam>
        /// <param name="overridedArguments">The overrided arguments.</param>
        /// <returns>The service instance.</returns>
        public T GetService<T>(object overridedArguments)
        {
            var overrides = GetParameterOverrides(overridedArguments);
            return Container.Resolve<T>(overrides.ToArray());
        }

        /// <summary>
        ///     Gets the service instance with the given type by using the overrided arguments.
        /// </summary>
        /// <param name="serviceType">The type of the service.</param>
        /// <param name="overridedArguments">The overrided arguments.</param>
        /// <returns>The service instance.</returns>
        public object GetService(Type serviceType, object overridedArguments)
        {
            var overrides = GetParameterOverrides(overridedArguments);
            return Container.Resolve(serviceType, overrides.ToArray());
        }
        public IEnumerable<T> GetServiceAll<T>()
        {

            return Container.ResolveAll<T>();
        }
        #endregion

        #region IServiceProvider Members

        /// <summary>
        ///     Gets the service instance with the given type.
        /// </summary>
        /// <param name="serviceType">The type of the service.</param>
        /// <returns>The service instance.</returns>
        public object GetService(Type serviceType)
        {
            return Container.Resolve(serviceType);
        }

        #endregion

        #region RegisterType

        public static void RegisterType<TFrom, TTo>(
            params InjectionMember[] injectionMembers) where TTo : TFrom
        {
            Container.RegisterType<TFrom, TTo>(injectionMembers);
        }
        public static void RegisterType(Type from, Type to, params InjectionMember[] injectionMembers)
        {
            Container.RegisterType(from, to, injectionMembers);
        }

        public static void RegisterType<TFrom, TTo>(LifetimeManager lifetimeManager,
            params InjectionMember[] injectionMembers) where TTo : TFrom
        {
            Container.RegisterType<TFrom, TTo>(lifetimeManager, injectionMembers);
        }

        public static void RegisterType<TFrom, TTo>(string name) where TTo : TFrom
        {
            Container.RegisterType<TFrom, TTo>(name);
        }
        #endregion
    }
}